package com.jl.magic.montage;

import com.jl.exceptions.MontageException;
import com.jl.jtils.file.FileUtils;
import com.jl.magic.enums.ShapeEnum;
import com.jl.magic.enums.SyntheticStyleEnum;
import com.jl.magic.montage.compose.AbstractSynthesizer;
import com.jl.magic.montage.config.AbstractInlayConfig;
import com.jl.magic.montage.model.Inlay;
import com.jl.magic.montage.model.MontageConfig;
import com.jl.magic.montage.model.SubImage;
import com.jl.magic.montage.slicer.AbstractSlicer;
import com.jl.magic.montage.tessera.AbstractInlayHandler;
import net.coobird.thumbnailator.Thumbnails;
import org.imgscalr.Scalr;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * @author jiangli
 * 蒙太奇图片client
 */
public class MontageClient {

    /**
     * 配置
     */
    private final MontageConfig montageConfig;

    /**
     * 源图片
     */
    private BufferedImage source;

    /**
     * 切片数量（分割后的子图数量）
     */
    private int sliceCount;

    /**
     * 镶元图片是否做压缩处理
     */
    private boolean compressed = true;

    private List<File> images;

    public MontageClient(MontageConfig montageConfig) {
        this.montageConfig = montageConfig;
    }

    public void build() throws MontageException, IOException {
        long start = System.currentTimeMillis();
        preCheck();
        long end1 = System.currentTimeMillis();
        System.out.println("---预处理耗时: " + (end1 - start) + "ms");

        initialize();
        long end2 = System.currentTimeMillis();
        System.out.println("---初始化耗时: " + (end2 - end1) + "ms");

        AbstractInlayConfig inlayConfig = montageConfig.getInlayConfig();
        ShapeEnum shapeEnum = inlayConfig.getInlayShapeEnum();

        StrategyFactory factory;
        switch (shapeEnum) {
            case SQUARE:
                factory = new SquareFactory();
                break;
            case CIRCLE:
                factory = new CircleFactory();
                break;
            default:
                throw new MontageException("合成形状不存在: " + shapeEnum.getName());
        }
        long end3 = System.currentTimeMillis();
        System.out.println("初始化工厂类耗时：" + (end3 - end2) + "ms");

        AbstractSlicer slicer = factory.createSlicer(source, inlayConfig, sliceCount);
        List<SubImage> subImageList = slicer.divide();
        long end4 = System.currentTimeMillis();
        System.out.println("源图分割耗时：" + (end4 - end3) + "ms，分割子图个数：" + subImageList.size());

        AbstractInlayHandler inlayHandler = factory.createInlayHandler(images, inlayConfig, compressed);
        List<Inlay> inlayList = inlayHandler.handleInlay();
        long end5 = System.currentTimeMillis();
        System.out.println("镶元图片处理耗时：" + (end5 - end4) + "ms，镶元图片个数：" + inlayList.size());

        AbstractSynthesizer synthesizer = factory.createSynthesizer(subImageList, inlayList, inlayConfig);
        BufferedImage compose = synthesizer.compose();
        long end6 = System.currentTimeMillis();
        System.out.println("图片合成处理耗时：" + (end6 - end5) + "ms");

        int width = compose.getWidth();
        width = width / 2;
        int height = compose.getHeight();
        height = height / 2;
        BufferedImage resize = Scalr.resize(compose, width, height);

        Thumbnails.of(resize).scale(0.25f).toFile(new File(montageConfig.getTarget()));
        long end7 = System.currentTimeMillis();
        System.out.println("图片缩放耗时：" + (end7 - end6) + "ms");

        /*try {
            FileUtils.buildImgFile(scale, FileType.JPG.getExtension().toLowerCase(), montageConfig.getTarget());
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        long end8 = System.currentTimeMillis();
        System.out.println("图片生成文件耗时：" + (end8 - end7) + "ms");

    }

    private void preCheck() throws MontageException {

        AbstractInlayConfig inlayConfig = montageConfig.getInlayConfig();
        if (null == inlayConfig) {
            throw new MontageException("缺少镶元图片配置");
        }

        ShapeEnum shapeEnum = inlayConfig.getInlayShapeEnum();
        SyntheticStyleEnum[] styles = inlayConfig.getSyntheticStyleEnum();
        if (null != styles) {
            for (SyntheticStyleEnum style : styles) {
                if (!shapeEnum.contains(style)) {
                    String format = String.format("镶元图片形状[%s]不支持[%s]合成风格", shapeEnum.getName(), style.getName());
                    throw new MontageException(format);
                }
            }
        }
    }

    private void initialize() throws MontageException {
        long start = System.currentTimeMillis();
        try {
            File file = new File(montageConfig.getSource());
            source = ImageIO.read(file);
        } catch (Exception e) {
            throw new MontageException("源图片读取失败", e);
        }

        int width = source.getWidth();
        int height = source.getHeight();
        int sourceMinWidth = 300;
        int sourceMinHeight = 300;
        if (width < sourceMinWidth || height < sourceMinHeight) {
            throw new MontageException("源图片的宽不能小于 " + sourceMinWidth + ", 高不能小于 " + sourceMinHeight);
        }
        long end1 = System.currentTimeMillis();
        System.out.println("源图读取耗时: " + (end1 - start) + "ms");

        images = FileUtils.getFiles(montageConfig.getInlayPath(), Arrays.asList(MontageConfig.INLAY_FILE_TYPES));
        int minInlayCount = 10;
        int maxInlayCount = 1000;
        if (images.size() < minInlayCount || images.size() > maxInlayCount) {
            throw new MontageException(String.format("镶嵌图片数量不能少于%d张, 且不能大于%d张", minInlayCount, maxInlayCount));
        }
        long end2 = System.currentTimeMillis();
        System.out.println("镶嵌图片读取耗时: " + (end2 - end1) + "ms");

        sliceCount = montageConfig.getSliceCount();
        int minSliceCount = 100;
        if (sliceCount < minSliceCount) {
            throw new MontageException("分割子图数量不能小于100");
        }
        compressed = montageConfig.isCompressed();

    }

}
